はじめに
TEditorMX(テキストエディタ)を使って正規表現について解説いたします。
作った自分で申すのもなんですがTEditorMX ver1.41(以降)の正規表現検索&置換は結構まともに動作して強力なものになっていると思います。
そのためこれから勉強したいという方には特にお勧めです。
キーボード検索を用いればどのパターンとマッチ(一致)するのかが良くご理解頂けると思います。
なお、正規表現には大きく分けで2種類の書き方がありますが、私が「書きやすいかな」と思った方で作りました。
本来であれば両方対応できれば良いのですがバグが怖かったので...そうしました。
以下の解説ではTEditorMX ver1.41(以降)を使用しますのでインストールされていない方はダウンロードページよりダウンロードしてインストールして下さい。
※ver1.41に付属するTEMXetc.dllに不具合がありまして、ver1.41で追加しました新機能で正しい結果が得られません。不具合ページをご参照の上、新しいDLLをダウンロードしてインストールして(差し替えて)下さい。
お手数をおかけして申し訳ありません。
お願い:正規表現のキーボード検索は下方向にしか検索できません。そのため最下部まで検索処理が到達(『マッチする文字列は見つかりませんでした』と表示された場合)したときには
恐れ入りますがファイルの先頭までキャレットを移動して下さい。
正規表現一覧
(1).(ピリオド)
(2)*
(3)+
(4)(pattern)
(5)(?:pattern)
(6)x|y
(7){min,max}
(8)[xyz]
(9)^, $
(10)\d
(11)\s
(12)(?=pattern)
(13)(?!pattern)
(14)(?<=pattern)
(15)(?<!pattern)
(16)??, *?, *+, {min,max}?
(17)\1~\9
(18)\
※この一覧には無い正規表現がありますが使用頻度は比較的低いと思いますので割愛させて頂きます。
※一部、TEditorMXの独自仕様があります(改行コードは常に \r\n など)。詳しくはTEditorMX付属のヘルプをご覧下さい。
(1).(ピリオド)
.(ピリオド)は改行コード以外の1文字とマッチします。
<< では実際にやって確認しましょう >>
サンプルプログラム(sample1.cpp)をTeditorMXで開いて下画像のようにツールバーの検索文字列に .(ピリオド)1文字を入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)※1を実行してみて下さい。
- ※1
- (Ctrl+Down)とはCtrlキーとキャレットキーの下(Down)を同時に押すことです。 この場合Ctrlキーとキャレットキーの下(Down)を同時に押すことで下方向に検索処理が実行されます。 その都度ポップアップメニューを開いて項目を選択しなくても簡単に検索処理を実行することができます。
実行するたびに1文字毎にマッチ(選択範囲が移動)していきます。
ただし、改行コードとはマッチしませんので改行コードは飛ばされます。
もし、「良く分からない」という場合にはポップアップメニューの【置換】(Ctrl+Shift+R)で文字列置換ダイアログを開いて検索文字列に同様の設定をし、
置換文字列に適当な文字(ここではイコール = )を指定し、置換を実行してみて下さい。
改行コード以外の文字がすべてイコール(=)に置換されるのが確認できると思います。
置換ダイアログ設定
置換前(test_period.txt)
a bc def あいうえお
置換後
= == === =====
置換文字列(=)の数を数えれば半角文字(アルファベット)と全角文字(ひらがな)に関係なく、各文字一つ一つと .(ピリオド)がマッチしていることが確認できると思います。
(2)*
前のパターンの0回以上の繰り返しにマッチします。0回以上なので空文字列ともマッチします。
空文字列とは各文字の左側※2にあると仮定している文字数0の実体のない文字列のことです。
「空文字列とマッチ」と表現されているときは文字の左側にあると仮定している文字数0の実体のない文字列とマッチしているということです。
- ※2
- 正確には文字の周りのあらゆるところにあるとされていますが処理の都合上、文字の左側にのみあるものと仮定しています。
<< では実際にやって確認しましょう >>
サンプルプログラム(sample1.cpp)をTEditorMXで開いて下画像のようにツールバーの検索文字列に .* と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するたびにキャレット以降の文字列または行頭以降の文字列(改行コードは含まれません)と改行コードの手前の空文字列とが交互にマッチするのが確認できると思います
(空文字列は実体がないので選択状態にはなりませんがキャレットがその位置で止まります)。
これは . が改行コード以外の文字とマッチし、* はその0回以上の繰り返しで更に最長マッチ※3というルールがあるため改行コードを含まない行全体が選択状態になります。
また、その後に続けて実行すると選択されていた文字列と改行コードの間にある空文字列とマッチするためそこでキャレットが止まります。
以降、それの繰り返しになります。
- ※3
- 最長マッチは「マッチする文字列の中で一番長い文字列とマッチする」というルールです。 最長マッチというルールがあるおかげで常に同じ検索結果が得られるようになっています。
(3)+
前のパターンの1回以上の繰り返しにマッチします。1回以上なので空文字列とはマッチしません。
<< では実際にやって確認しましょう >>
サンプルプログラム(sample1.cpp)をTEditorMXで開いて下画像のようにツールバーの検索文字列に .+ と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するたびにキャレット以降の文字列または行全体(改行コードは含まれません)がマッチするのが確認できると思います
これは . が改行コード以外の文字とマッチし、+ はその1回以上の繰り返しで更に最長マッチというルールがあるため(改行コードは含まれません)行全体が選択状態になります。
また + は1回以上なので改行コードしか含まれない行はパスされます(マッチしません)。
以降、実行するとこれらの繰り返しになります。
(4)(pattern)
グルーピング。patternをひとまとまりの正規表現とします。 例えば (abc)+ とした場合には、1個以上の abc とマッチしますので、
abc abcabc abcabcabc
の何れにもマッチします。
また、優先順位を替えるためにも使用できます。
東京ドーム 東京タワー 東京駅 東京スカイツリー 東京都
の中から「東京スカイツリー」と「東京駅」を検索したい場合を考えます。
東京スカイツリー|駅
と記述してしまうと「東京スカイツリー」と「駅」にマッチして上手く検索できません。
そこでグルーピングを用いて、
東京(スカイツリー|駅)
と記述すると今度は「東京スカイツリー」と「東京駅」の両方を上手く検索することができます。
※『スカイツリー』と『駅』の間にある | は OR でこの後の方に出てきます。
グルーピングとしての機能のほかに後方参照データを取得する目的でも使用します。
詳しくは後方参照をご覧下さい。
(5)(?:pattern)
グルーピング(キャプチャ無し)。使い方は普通のグルーピングと同じですがキャプチャ無しです。
「キャプチャ無し」とは後方参照(\1~\9)に対応する文字列を保持しないということです。
つまり後方参照(\1~\9)にマッチ文字列は割り当てられません。
(6)x|y
正規表現 x または y にマッチします(OR)。
<< では実際にやって確認しましょう >>
サンプルプログラム(sample1.cpp)をTeditorMXで開き、ポップアップメニューの【検索】を選択して文字列検索ダイアログを表示させます。
続いて下画像のように検索文字列に unsigned (char|short) と入力し、正規表現チェックボックスにチェックを入れて下さい。
入力し終わったら検索開始ボタンを押して検索を実行してみて下さい。
正しく入力されていれば情報ウィンドウの検索結果タブに下画像のような結果が表示されると思います。
マッチした行(3行)が表示されます。
74行と90行は unsigned char にマッチし、95行は unsigned short にマッチしました。
ORになっていますね。
(7){min,max}
直前の正規表現の指定回数(min以上、max以下)の繰り返しにマッチします。
minとmaxは入れ替えても動作します。
{number} と指定するとnumber回ちょうどの繰り返しとマッチします。
<< では実際にやって確認しましょう >>
テキストファイル(repeat.txt)をTEditorMXで開き、ポップアップメニューの【検索】を選択して文字列検索ダイアログを表示させます。
続いて下画像のように検索文字列に (abc){2,3} と入力し、正規表現チェックボックスにチェックを、入れて下さい。
入力し終わったら検索開始ボタンを押して検索を実行してみて下さい。
正しく入力されていれば情報ウィンドウの検索結果タブに下画像のような結果が表示されると思います。
マッチした行が3行表示されます。
え?2行じゃないの?と思われたかもしれませんが3行で良いのです。
2行、3行は{2,3}の範囲内なのでマッチして当然ですが、4行も行頭から3回目の繰り返しまでマッチします。
試しに4行をダブルクリックしてタグジャンプしてみて下さい。
マッチした文字列(選択されている文字列)は先頭から3回目までの繰り返しまでになっているのが確認できると思います(下画像)。
『え~、4回の繰り返しなんだからマッチさせないでよ~』と思われた方、これは仕様なのでご容赦下さい。
もし4回以上の繰り返しとマッチさせたくないときには ver1.41で設けた新機能:否定の先読みをご利用ください。
書き方だけ示しておきますと (abc){2,3}(?!abc) と記述することで4回目以降の繰り返しがあった場合にはマッチしないようになります。
...でもこれ、あまり意味がないかもしれません。やってみると分かりますが一番最後の3回繰り返しの部分が必ずマッチするからです。
(8)[xyz]
キャラクタリスト。指定されたxyzの中の何れかにマッチします。
ハイフン(-)で範囲指定することも可能です。[0-9]と記述すると数字1文字にマッチしますし、[A-Za-z]と記述しますとアルファベットの1文字とマッチします。
2バイト文字にも対応しています。[あ-お]と記述しますとひらがなの「あぃいぅうぇえぉお」の中のいずれか1文字とマッチします。
文字コードはASCIIコード(半角文字)とシフトJISコード(全角文字)を用いることができます。文字コードはWindows付属のIME等で確認できますのでご覧下さい。
否定
キャラクタリストの先頭に ^ を置くと否定になります。
例えば [^0-9] と記述しますと数字以外の文字とマッチしますし、[^A-Za-z]と記述しますとアルファベット以外の文字とマッチします。
もし改行コードを指定したいときは必ず \r\n を指定して下さい。これはTEditorMXの独自仕様です。
<< では実際にやって確認しましょう >>
テキストファイル(charlist.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に [0-9] と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するたびに数字1文字が次々とマッチ(選択範囲が移動)していきます。
[A-Z]、[ぁ-ん]、などいろいろ試してみて下さいね。
ひとつ書き忘れました。上の例(画像)では区別チェックボックスにチェックを入れていませんのでアルファベットの大文字・小文字は区別されません。
区別したいときはチェックして下さい。
(9)^, $
^ は行頭にマッチします。
$ は改行コードの直前、改行コードが無いときは行末にマッチします。
<< では実際にやって確認しましょう >>
テキストファイル(sample1.cpp)をTeditorMXで開いて下画像のようにツールバーの検索文字列に ^HANDLE と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
行頭にある HANDLE という文字列にのみマッチするのが分かると思います。
また同様に検索文字列として ^$ と入力して同様に検索を実行してみて下さい。
^$は行頭と行末がくっついている状態・・・つまり改行コード以外何の文字も含まれない空行とマッチします。
何もない行とマッチしますのでキャレットが移動するだけになります。
(10)\d
アラビア数字[0-9]1文字とマッチします。
(11)\s
空白文字[ \f\n\r\t\v]とマッチします。
(12)(?=pattern)
肯定の先読み。patternが右側に存在するときマッチします。
先読みですのでマッチデータには含まれませんしキャプチャもされません。
<< では実際にやって確認しましょう >>
テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に windows(?=\s10) と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するとwindows 10のwindowsにのみマッチします。
(13)(?!pattern)
否定の先読み。patternが右側に存在しないときマッチします。
先読みですのでマッチデータには含まれませんしキャプチャもされません。
<< では実際にやって確認しましょう >>
テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に windows(?!\s10) と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するとwindows 10以外のwindowsにマッチします。
(14)(?<=pattern)
肯定の戻り読み。patternが左側に存在するときマッチします。
戻り読みですのでマッチデータには含まれませんしキャプチャもされません。
<< では実際にやって確認しましょう >>
テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に (?<=sd)ram と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するとsdramのramにのみマッチします。
(15)(?<!pattern)
否定の戻り読み。patternが左側に存在しないときマッチします。
戻り読みですのでマッチデータには含まれませんしキャプチャもされません。
<< では実際にやって確認しましょう >>
テキストファイル(lookreturn.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に (?<!sd)ram と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行するとsdram以外のramにマッチします。
(16)??, *?, +?, {min,max}?
繰り返しの正規表現に続けて ? を記述すると最短マッチになります。
通常は『最長マッチ』です。『最長マッチ』とはマッチするデータの中で最長のものをマッチデータとすることです。
それに対して『最短マッチ』はマッチデータの中で最短となるものをマッチデータとします。
どのようなときに用いるのか...と言いますと例えば次のようなHTMLのタグを検索するときを考えます。
<a href="#..."> comment .... </a>
最初の <a href="#..."> を検索(マッチ)させたいとした場合に <a\s.*> という正規表現で検索したとします。
すると最長マッチですので行末に記述されている終了タグの > までマッチしてしまいます。
これでは上手くありません。
このようなときに『最短マッチ』の出番です。
繰り返しの正規表現 * の後に ? を付けて <a\s.*?> とします。
これで検索を実行しますと上手く検索(マッチ)させることができます。
<< では実際にやって確認しましょう >>
テキストファイル(saitann.txt)をTeditorMXで開いて下画像のようにツールバーの検索文字列に <a\s.*> と入力し、正規チェックボックスにチェックを入れ、
編集メニューの【キーボード検索→下方向検索】(Ctrl+Down)を実行してみて下さい。
実行すると最長マッチですので終了タグまで(行全体)がマッチしてしまいます。
<a href="#..."> comment .... </a> ← 行全体がマッチしてしまう
続いて繰り返しの正規表現に ? を付けて <a\s.*?> と入力し、実行してみて下さい。
今度は commentの前の > までがマッチして期待通りの動作をします。
<a href="#..."> comment .... </a> ← 期待通りにマッチ
(17)\1~\9
\1~\9は後方参照と呼ばれ、検索時にグルーピング (pattern) の中の正規表現とマッチした文字列に置き換えられます。
\1, \2等の番号は左側から順番に数えたときの出現位置になります。
(abc)de(fgh)ij(klm)(nopqr)
として検索したときに得られる後方参照は、
\1 = abc
\2 = fgh
\3 = klm
\4 = nopqr
となります。
また、グルーピング(キャプチャ無し)(?:pattern) を用いますとキャプチャされませんので次のようになります。
(abc)de(?:fgh)ij(?:klm)(nopqr)
として検索したときに得られる後方参照は、
\1 = abc
\2 = nopqr
となります。
その他、文字列置換時(置換文字列)にだけ用いることができる後方参照 \0 があります。
\0 は、マッチデータすべての文字列を表します。
余談ですが、私の場合、後方参照は文字列検索時よりも文字列置換時に用いることが多いです。 「ある文字列にこの文字列を追加したい」とか「ある文字列からこの文字列を削除したい」とかいうときがよくあります。 そのようなときに『文字列置換+後方参照』は強力な武器になってくれます。
(18)\
メタ文字の持つ特別な意味を失わせます。
例
\. → ただの .(ピリオド) \* → ただの *(アスタリスク) \( → ただの前括弧 ( \) → ただの閉じ括弧 )